home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / math / c-eval / ee.c < prev    next >
Text File  |  1993-04-22  |  27KB  |  769 lines

  1. /*************************************************************************
  2. **                                                                       **
  3. ** EE.C         Expression Evaluator                                     **
  4. **                                                                       **
  5. ** AUTHOR:      Mark Morley                                              **
  6. ** COPYRIGHT:   (c) 1992 by Mark Morley                                  **
  7. ** DATE:        December 1991                                            **
  8. ** HISTORY:     Jan 1992 - Made it squash all command line arguments     **
  9. **                         into one big long string.                     **
  10. **                       - It now can set/get VMS symbols as if they     **
  11. **                         were variables.                               **
  12. **                       - Changed max variable name length from 5 to 15 **
  13. **              Jun 1992 - Updated comments and docs                     **
  14. **                                                                       **
  15. ** You are free to incorporate this code into your own works, even if it **
  16. ** is a commercial application.  However, you may not charge anyone else **
  17. ** for the use of this code!  If you intend to distribute your code,     **
  18. ** I'd appreciate it if you left this message intact.  I'd like to       **
  19. ** receive credit wherever it is appropriate.  Thanks!                   **
  20. **                                                                       **
  21. ** I don't promise that this code does what you think it does...         **
  22. **                                                                       **
  23. ** Please mail any bug reports/fixes/enhancments to me at:               **
  24. **      morley@camosun.bc.ca                                             **
  25. ** or                                                                    **
  26. **      Mark Morley                                                      **
  27. **      3889 Mildred Street                                              **
  28. **      Victoria, BC  Canada                                             **
  29. **      V8Z 7G1                                                          **
  30. **      (604) 479-7861                                                   **
  31. **                                                                       **
  32.  *************************************************************************/
  33.  
  34. /* #define VAX */             /* Uncomment this line if you're using VMS */
  35.  
  36. #include <stdlib.h>
  37. #include <math.h>
  38. #include <setjmp.h>
  39.  
  40. #ifdef VAX
  41. #include <ssdef.h>
  42. #include <descrip.h>
  43. #endif
  44.  
  45. #include "ee.h"
  46.  
  47. #define ERR(n) {ERROR=n; ERPOS=expression-ERANC-1; strcpy(ERTOK,token); longjmp(jb,1);}
  48.  
  49. /* These defines only happen if the values are not already defined!  You may
  50.    want to add more precision here, if your machine supports it. */
  51. #ifndef M_PI
  52. #define M_PI    3.14159265358979323846
  53. #endif
  54. #ifndef M_E
  55. #define M_E     2.71828182845904523536
  56. #endif
  57.  
  58.  
  59. /*************************************************************************
  60. **                                                                       **
  61. ** PROTOTYPES FOR CUSTOM MATH FUNCTIONS                                  **
  62. **                                                                       **
  63.  *************************************************************************/
  64.  
  65. double deg( double x );
  66. double rad( double x );
  67.  
  68.  
  69. /*************************************************************************
  70. **                                                                       **
  71. ** VARIABLE DECLARATIONS                                                 **
  72. **                                                                       **
  73.  *************************************************************************/
  74.  
  75. int   ERROR;                 /* The error number */
  76. char  ERTOK[TOKLEN + 1];     /* The token that generated the error */
  77. int   ERPOS;                 /* The offset from the start of the expression */
  78. char* ERANC;                 /* Used to calculate ERPOS */
  79.  
  80. /*
  81.    Add any "constants" here...  These are "read-only" values that are
  82.    provided as a convienence to the user.  Their values can not be
  83.    permanently changed.  The first field is the variable name, the second
  84.    is its value.
  85. */
  86. VARIABLE Consts[] =
  87. {
  88.    /* name, value */
  89.    { "pi",      M_PI },
  90.    { "e",       M_E },
  91.  
  92.    { 0 }
  93. };
  94.  
  95. /*
  96.    Add any math functions that you wish to recognise here...  The first
  97.    field is the name of the function as it would appear in an expression.
  98.    The second field tells how many arguments to expect.  The third is
  99.    a pointer to the actual function to use.
  100. */
  101. FUNCTION Funcs[] =
  102. {
  103.    /* name, funtion to call */
  104.    { "sin",     1,    sin },
  105.    { "cos",     1,    cos },
  106.    { "tan",     1,    tan },
  107.    { "asin",    1,    asin },
  108.    { "acos",    1,    acos },
  109.    { "atan",    1,    atan },
  110.    { "sinh",    1,    sinh },
  111.    { "cosh",    1,    cosh },
  112.    { "tanh",    1,    tanh },
  113.    { "exp",     1,    exp },
  114.    { "log",     1,    log },
  115.    { "log10",   1,    log10 },
  116.    { "sqrt",    1,    sqrt },
  117.    { "floor",   1,    floor },
  118.    { "ceil",    1,    ceil },
  119.    { "abs",     1,    fabs },
  120.    { "hypot",   2,    hypot },
  121.  
  122.    { "deg",     1,    deg },
  123.    { "rad",     1,    rad },
  124.  
  125.    { 0 }
  126. };
  127.  
  128. VARIABLE        Vars[MAXVARS];       /* Array for user-defined variables */
  129. unsigned char*  expression;          /* Pointer to the user's expression */
  130. unsigned char   token[TOKLEN + 1];   /* Holds the current token */
  131. int             type;                /* Type of the current token */
  132. jmp_buf         jb;                  /* jmp_buf for errors */
  133.  
  134.  
  135. /*************************************************************************
  136. **                                                                       **
  137. ** Some custom math functions...   Note that they must be prototyped     **
  138. ** above (if your compiler requires it)                                  **
  139. **                                                                       **
  140. ** deg( x )             Converts x radians to degrees.                   **
  141. ** rad( x )             Converts x degrees to radians.                   **
  142. **                                                                       **
  143.  *************************************************************************/
  144.  
  145. double
  146. deg( double x )
  147. {
  148.    return( x * 180.0 / M_PI );
  149. }
  150.  
  151. double
  152. rad( double x )
  153. {
  154.    return( x * M_PI / 180.0 );
  155. }
  156.  
  157.  
  158. /*************************************************************************
  159. **                                                                       **
  160. ** GetSymbol( char* s )                                                  **
  161. **                                                                       **
  162. ** This routine obtains a value from the program's environment.          **
  163. ** This works for DOS and VMS (and other OS's???)
  164. **                                                                       **
  165.  ************************************************************************/
  166.  
  167. GetSymbol( char* s, TYPE* v )
  168. {
  169.    char* e;
  170.  
  171.    e = getenv( s );
  172.    if( !e )
  173.       return( 0 );
  174.    *v = atof( e );
  175.    return( 1 );
  176. }
  177.  
  178.  
  179. /*************************************************************************
  180. **                                                                       **
  181. ** SetSymbol( char* s, char* v )                                         **
  182. **                                                                       **
  183. ** This VMS specific routine sets (or updates) a VMS symbol to a given   **
  184. ** value                                                                 **
  185. **                                                                       **
  186.  *************************************************************************/
  187.  
  188. #ifdef VAX
  189. SetSymbol( char* s, char* v )
  190. {
  191.    struct dsc$descriptor_s sym;
  192.    struct dsc$descriptor_s val;
  193.    long                    typ = 1;
  194.  
  195.    sym.dsc$w_length = strlen( s );
  196.    sym.dsc$a_pointer = s;
  197.    sym.dsc$b_class = DSC$K_CLASS_S;
  198.    sym.dsc$b_dtype = DSC$K_DTYPE_T;
  199.    val.dsc$w_length = strlen( v );
  200.    val.dsc$a_pointer = v;
  201.    val.dsc$b_class = DSC$K_CLASS_S;
  202.    val.dsc$b_dtype = DSC$K_DTYPE_T;
  203.    return( LIB$SET_SYMBOL( &sym, &val, &typ ) );
  204. }
  205. #endif
  206.  
  207.  
  208. /*************************************************************************
  209. **                                                                       **
  210. ** strlwr( char* s )   Internal use only                                 **
  211. **                                                                       **
  212. ** This routine converts a string to lowercase.  I know many compilers   **
  213. ** offer their own routine, but my VMS compiler didn't so...             **
  214. ** Again, this one is ASCII specific!                                    **
  215. **                                                                       **
  216.  *************************************************************************/
  217.  
  218. static
  219. strlwr( char* s )
  220. {
  221.    while( *s )
  222.    {
  223.       if( *s >= 'A' && *s <= 'Z' )
  224.          *s += 32;
  225.       s++;
  226.    }
  227. }
  228.  
  229.  
  230. /*************************************************************************
  231. **                                                                       **
  232. ** ClearAllVars()                                                        **
  233. **                                                                       **
  234. ** Erases all user-defined variables from memory. Note that constants    **
  235. ** can not be erased or modified in any way by the user.                 **
  236. **                                                                       **
  237. ** Returns nothing.                                                      **
  238. **                                                                       **
  239.  *************************************************************************/
  240.  
  241. ClearAllVars()
  242. {
  243.    int i;
  244.  
  245.    for( i = 0; i < MAXVARS; i++ )
  246.    {
  247.       *Vars[i].name = 0;
  248.       Vars[i].value = 0;
  249.    }
  250. }
  251.  
  252.  
  253. /*************************************************************************
  254. **                                                                       **
  255. ** ClearVar( char* name )                                                **
  256. **                                                                       **
  257. ** Erases the user-defined variable that is called NAME from memory.     **
  258. ** Note that constants are not affected.                                 **
  259. **                                                                       **
  260. ** Returns 1 if the variable was found and erased, or 0 if it didn't     **
  261. ** exist.                                                                **
  262. **                                                                       **
  263.  *************************************************************************/
  264.  
  265. ClearVar( char* name )
  266. {
  267.    int i;
  268.  
  269.    for( i = 0; i < MAXVARS; i++ )
  270.       if( *Vars[i].name && ! strcmp( name, Vars[i].name ) )
  271.       {
  272.          *Vars[i].name = 0;
  273.          Vars[i].value = 0;
  274.          return( 1 );
  275.       }
  276.    return( 0 );
  277. }
  278.  
  279.  
  280. /*************************************************************************
  281. **                                                                       **
  282. ** GetValue( char* name, TYPE* value )                                   **
  283. **                                                                       **
  284. ** Looks up the specified variable (or constant) known as NAME and       **
  285. ** returns its contents in VALUE.                                        **
  286. **                                                                       **
  287. ** First the user-defined variables are searched, then the constants are **
  288. ** searched.                                                             **
  289. **                                                                       **
  290. ** Returns 1 if the value was found, or 0 if it wasn't.                  **
  291. **                                                                       **
  292.  *************************************************************************/
  293.  
  294. GetValue( char* name, TYPE* value )
  295. {
  296.    int i;
  297.  
  298.    /* First check for an environment variable reference... */
  299.    if( *name == '_' )
  300.       return( GetSymbol( name + 1, value ) );
  301.  
  302.    /* Now check the user-defined variables. */
  303.    for( i = 0; i < MAXVARS; i++ )
  304.       if( *Vars[i].name && ! strcmp( name, Vars[i].name ) )
  305.       {
  306.          *value = Vars[i].value;
  307.          return( 1 );
  308.       }
  309.  
  310.    /* Now check the programmer-defined constants. */
  311.    for( i = 0; *Consts[i].name; i++ )
  312.       if( *Consts[i].name && ! strcmp( name, Consts[i].name ) )
  313.       {
  314.          *value = Consts[i].value;
  315.          return( 1 );
  316.       }
  317.    return( 0 );
  318. }
  319.  
  320.  
  321. /*************************************************************************
  322. **                                                                       **
  323. ** SetValue( char* name, TYPE* value )                                   **
  324. **                                                                       **
  325. ** First, it erases any user-defined variable that is called NAME.  Then **
  326. ** it creates a new variable called NAME and gives it the value VALUE.   **
  327. **                                                                       **
  328. ** Returns 1 if the value was added, or 0 if there was no more room.     **
  329. **                                                                       **
  330.  *************************************************************************/
  331.  
  332. SetValue( char* name, TYPE* value )
  333. {
  334.    char b[30];
  335.    int  i;
  336.  
  337. #ifdef VAX
  338.    if( *name == '_' )
  339.    {
  340.       sprintf( b, "%g", *value );
  341.       if( SetSymbol( name + 1, b ) != SS$_NORMAL )
  342.          return( 0 );
  343.       return( 1 );
  344.    }
  345. #endif
  346.    ClearVar( name );
  347.    for( i = 0; i < MAXVARS; i++ )
  348.       if( ! *Vars[i].name )
  349.       {
  350.          strcpy( Vars[i].name, name );
  351.          Vars[i].name[VARLEN] = 0;
  352.          Vars[i].value = *value;
  353.          return( 1 );
  354.       }
  355.    return( 0 );
  356. }
  357.  
  358.  
  359. /*************************************************************************
  360. **                                                                       **
  361. ** Parse()   Internal use only                                           **
  362. **                                                                       **
  363. ** This function is used to grab the next token from the expression that **
  364. ** is being evaluated.                                                   **
  365. **                                                                       **
  366.  *************************************************************************/
  367.  
  368. static
  369. Parse()
  370. {
  371.    char* t;
  372.  
  373.    type = 0;
  374.    t = token;
  375.    while( iswhite( *expression ) )
  376.       expression++;
  377.    if( isdelim( *expression ) )
  378.    {
  379.       type = DEL;
  380.       *t++ = *expression++;
  381.    }
  382.    else if( isnumer( *expression ) )
  383.    {
  384.       type = NUM;
  385.       while( isnumer( *expression ) )
  386.          *t++ = *expression++;
  387.    }
  388.    else if( isalpha( *expression ) )
  389.    {
  390.       type = VAR;
  391.       while( isalpha( *expression ) )
  392.         *t++ = *expression++;
  393.       token[VARLEN] = 0;
  394.    }
  395.    else if( *expression )
  396.    {
  397.       *t++ = *expression++;
  398.       *t = 0;
  399.       ERR( E_SYNTAX );
  400.    }
  401.    *t = 0;
  402.    while( iswhite( *expression ) )
  403.       expression++;
  404. }
  405.  
  406.  
  407. /*************************************************************************
  408. **                                                                       **
  409. ** Level1( TYPE* r )   Internal use only                                 **
  410. **                                                                       **
  411. ** This function handles any variable assignment operations.             **
  412. ** It returns a value of 1 if it is a top-level assignment operation,    **
  413. ** otherwise it returns 0                                                **
  414. **                                                                       **
  415.  *************************************************************************/
  416.  
  417. static
  418. Level1( TYPE* r )
  419. {
  420.    char t[VARLEN + 1];
  421.  
  422.    if( type == VAR )
  423.       if( *expression == '=' )
  424.       {
  425.          strcpy( t, token );
  426.          Parse();
  427.          Parse();
  428.          if( !*token )
  429.          {
  430.             ClearVar( t );
  431.             return(1);
  432.          }
  433.          Level2( r );
  434.          if( ! SetValue( t, r ) )
  435.             ERR( E_MAXVARS );
  436.          return( 1 );
  437.       }
  438.    Level2( r );
  439.    return( 0 );
  440. }
  441.  
  442.  
  443. /*************************************************************************
  444. **                                                                       **
  445. ** Level2( TYPE* r )   Internal use only                                 **
  446. **                                                                       **
  447. ** This function handles any addition and subtraction operations.        **
  448. **                                                                       **
  449.  *************************************************************************/
  450.  
  451. static
  452. Level2( TYPE* r )
  453. {
  454.    TYPE t = 0;
  455.    char o;
  456.  
  457.    Level3( r );
  458.    while( (o = *token) == '+' || o == '-' )
  459.    {
  460.       Parse();
  461.       Level3( &t );
  462.       if( o == '+' )
  463.          *r = *r + t;
  464.       else if( o == '-' )
  465.          *r = *r - t;
  466.    }
  467. }
  468.  
  469.  
  470. /*************************************************************************
  471. **                                                                       **
  472. ** Level3( TYPE* r )   Internal use only                                 **
  473. **                                                                       **
  474. ** This function handles any multiplication, division, or modulo.        **
  475. **                                                                       **
  476.  *************************************************************************/
  477.  
  478. static
  479. Level3( TYPE* r )
  480. {
  481.    TYPE t;
  482.    char o;
  483.  
  484.    Level4( r );
  485.    while( (o = *token) == '*' || o == '/' || o == '%' )
  486.    {
  487.       Parse();
  488.       Level4( &t );
  489.       if( o == '*' )
  490.          *r = *r * t;
  491.       else if( o == '/' )
  492.       {
  493.          if( t == 0 )
  494.             ERR( E_DIVZERO );
  495.          *r = *r / t;
  496.       }
  497.       else if( o == '%' )
  498.       {
  499.          if( t == 0 )
  500.             ERR( E_DIVZERO );
  501.          *r = fmod( *r, t );
  502.       }
  503.    }
  504. }
  505.  
  506.  
  507. /*************************************************************************
  508. **                                                                       **
  509. ** Level4( TYPE* r )   Internal use only                                 **
  510. **                                                                       **
  511. ** This function handles any "to the power of" operations.               **
  512. **                                                                       **
  513.  *************************************************************************/
  514.  
  515. static
  516. Level4( TYPE* r )
  517. {
  518.    TYPE t;
  519.  
  520.    Level5( r );
  521.    if( *token == '^' )
  522.    {
  523.       Parse();
  524.       Level5( &t );
  525.       *r = pow( *r, t );
  526.    }
  527. }
  528.  
  529.  
  530. /*************************************************************************
  531. **                                                                       **
  532. ** Level5( TYPE* r )   Internal use only                                 **
  533. **                                                                       **
  534. ** This function handles any unary + or - signs.                         **
  535. **                                                                       **
  536.  *************************************************************************/
  537.  
  538. static
  539. Level5( TYPE* r )
  540. {
  541.    char o = 0;
  542.  
  543.    if( *token == '+' || *token == '-' )
  544.    {
  545.       o = *token;
  546.       Parse();
  547.    }
  548.    Level6( r );
  549.    if( o == '-' )
  550.       *r = -*r;
  551. }
  552.  
  553.  
  554. /*************************************************************************
  555. **                                                                       **
  556. ** Level6( TYPE* r )   Internal use only                                 **
  557. **                                                                       **
  558. ** This function handles any literal numbers, variables, or functions.   **
  559. **                                                                       **
  560.  *************************************************************************/
  561.  
  562. static
  563. Level6( TYPE* r )
  564. {
  565.    int  i;
  566.    int  n;
  567.    TYPE a[3];
  568.  
  569.    if( *token == '(' )
  570.    {
  571.       Parse();
  572.       if( *token == ')' )
  573.          ERR( E_NOARG );
  574.       Level1( r );
  575.       if( *token != ')' )
  576.          ERR( E_UNBALAN );
  577.       Parse();
  578.    }
  579.    else
  580.    {
  581.       if( type == NUM )
  582.       {
  583.          *r = (TYPE) atof( token );
  584.          Parse();
  585.       }
  586.       else if( type == VAR )
  587.       {
  588.          if( *expression == '(' )
  589.          {
  590.             for( i = 0; *Funcs[i].name; i++ )
  591.                if( ! strcmp( token, Funcs[i].name ) )
  592.                {
  593.                   Parse();
  594.                   n = 0;
  595.                   do
  596.                   {
  597.                      Parse();
  598.                      if( *token == ')' || *token == ',' )
  599.                         ERR( E_NOARG );
  600.                      a[n] = 0;
  601.                      Level1( &a[n] );
  602.                      n++;
  603.                   } while( n < 4 && *token == ',' );
  604.                   Parse();
  605.                   if( n != Funcs[i].args )
  606.                   {
  607.                      strcpy( token, Funcs[i].name );
  608.                      ERR( E_NUMARGS );
  609.                   }
  610.                   *r = Funcs[i].func( a[0], a[1], a[2] );
  611.                   return;
  612.                }
  613.                if( ! *Funcs[i].name )
  614.                   ERR( E_BADFUNC );
  615.             }
  616.             else if( ! GetValue( token, r ) )
  617.                ERR( E_UNKNOWN );
  618.          Parse();
  619.       }
  620.       else
  621.          ERR( E_SYNTAX );
  622.    }
  623. }
  624.  
  625.  
  626. /*************************************************************************
  627. **                                                                       **
  628. ** Evaluate( char* e, TYPE* result, int* a )                             **
  629. **                                                                       **
  630. ** This function is called to evaluate the expression E and return the   **
  631. ** answer in RESULT.  If the expression was a top-level assignment, a    **
  632. ** value of 1 will be returned in A, otherwise it will contain 0.        **
  633. **                                                                       **
  634. ** Returns E_OK if the expression is valid, or an error code.            **
  635. **                                                                       **
  636.  *************************************************************************/
  637.  
  638. Evaluate( char* e, TYPE* result, int* a )
  639. {
  640.    if( setjmp( jb ) )
  641.       return( ERROR );
  642.    expression = e;
  643.    ERANC = e;
  644.    strlwr( expression );
  645.    *result = 0;
  646.    Parse();
  647.    if( ! *token )
  648.       ERR( E_EMPTY );
  649.    *a = Level1( result );
  650.    return( E_OK );
  651. }
  652.  
  653.  
  654. /*************************************************************************
  655. **                                                                       **
  656. ** What follows is a main() routine that evaluates the command line      **
  657. ** arguments one at a time, and displays the results of each expression. **
  658. ** Without arguments, it becomes an interactive calculator.              **
  659. **                                                                       **
  660.  *************************************************************************/
  661.  
  662. #include <stdio.h>
  663.  
  664. char* ErrMsgs[] =
  665. {
  666.    "Syntax error",
  667.    "Unbalanced parenthesis",
  668.    "Division by zero",
  669.    "Unknown variable",
  670.    "Maximum variables exceeded",
  671.    "Unrecognised funtion",
  672.    "Wrong number of arguments to funtion",
  673.    "Missing an argument",
  674.    "Empty expression"
  675. };
  676.  
  677. main( int argc, char* argv[] )
  678. {
  679.    TYPE  result;
  680.    int   i;
  681.    int   ec;
  682.    int   a;
  683.    char  line[1024];
  684.    char* v;
  685.  
  686.    ClearAllVars();
  687.    /* If we have command line arguments then we evaluate them and exit. */
  688.    if( argc > 1 )
  689.    {
  690.       /* Concatenate all arguments into one string. */
  691.       strcpy( line, argv[1] );
  692.       for( i = 2; i < argc; i++ )
  693.          strcat( line, argv[i] );
  694.  
  695.       /* Call the evaluator. */
  696.       if( (ec = Evaluate( line, &result, &a )) == E_OK )
  697.       {
  698.          /* If we didn't assign a variable, then print the result. */
  699.          if( ! a )
  700.             printf( "%g\n", result );
  701.       }
  702.       else if( ec != E_EMPTY )
  703.       {
  704.          /* Display error info.  In this example, an E_EMPTY error is ignored. */
  705.          printf( "ERROR: %s - %s", ErrMsgs[ERROR - 1], ERTOK );
  706.          printf( "\n%s", ERANC );
  707.          printf( "\n%*s^\n", ERPOS, "" );
  708.       }
  709.       return;
  710.    }
  711.  
  712.    /* There were no command line arguments, so lets go interactive. */
  713.    printf( "\nEE - Equation Evaluator" );
  714.    printf( "\nBy Mark Morley  December 1991" );
  715.    printf( "\nEnter EXIT to quit.\n" );
  716.    printf( "\nEE> " );
  717.  
  718.    /* Input one line at a time from the user.  Note that it uses stdin, so on
  719.       DOS or UNIX you could pipe a list of expressions into it... */
  720.    for( gets( line ); !feof( stdin ); gets( line ) )
  721.    {
  722.       strlwr( line );
  723.  
  724.       /* Did the user ask to exit? */
  725.       if( ! strcmp( line, "exit" ) )
  726.          return;
  727.  
  728.       /* Did the user ask to see the variables in memory? */
  729.       else if( ! strcmp( line, "vars" ) )
  730.       {
  731.          for( i = 0; i < MAXVARS; i++ )
  732.             if( *Vars[i].name )
  733.                printf( "%s = %g\n", Vars[i].name, Vars[i].value );
  734.       }
  735.  
  736.       /* Did the user ask to see the constants in memory? */
  737.       else if( ! strcmp( line, "cons" ) )
  738.       {
  739.          for( i = 0; *Consts[i].name; i++ )
  740.             printf( "%s = %g\n", Consts[i].name, Consts[i].value );
  741.       }
  742.  
  743.       /* Did the user ask to clear all variables? */
  744.       else if( ! strcmp( line, "clr" ) )
  745.          ClearAllVars();
  746.  
  747.       /* If none of the above, then we attempt to evaluate the user's input. */
  748.       else
  749.       {
  750.          /* Call the evaluator. */
  751.          if( (ec = Evaluate( line, &result, &a )) == E_OK )
  752.          {
  753.             /* Only display the result if it was not an assignment. */
  754.             if( ! a )
  755.                printf( "%g\n", result );
  756.          }
  757.          else if( ec != E_EMPTY )
  758.          {
  759.             /* Display error information.  E_EMPTY is ignored. */
  760.             printf( "ERROR: %s - %s", ErrMsgs[ERROR - 1], ERTOK );
  761.             printf( "\n%s", ERANC );
  762.             printf( "\n%*s^\n", ERPOS, "" );
  763.          }
  764.       }
  765.       printf( "EE> " );
  766.    }
  767. }
  768.  
  769.